From 99cab9a77803cdb6a50de453ba1115f25973bf88 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 28 Feb 2006 17:45:20 +0100 Subject: [PATCH] Sketch a new interface for transferring hypercall arguments in memory. Instead of manipulating guest virtual addresses, 'guest handles' are passed across the hypercall interface, which may only be manipulated via the interface exported by guest_access.h. So far this has only been applied to the memory_op hypercall. The interfaces are still subject to change. Other hypercalls can be updated after the interface is agreed upon. Also cleaned up the hypercall_create_continuation() interface to take a format string and different-typed varargs (they do not all need to be castable to longs). Signed-off-by: Keir Fraser --- xen/Rules.mk | 2 +- xen/arch/ia64/vmx/vmx_hypercall.c | 40 +--------------- xen/arch/ia64/xen/process.c | 36 ++++++++++---- xen/arch/x86/domain.c | 55 +++++++++++++-------- xen/arch/x86/mm.c | 20 ++++---- xen/arch/x86/traps.c | 4 +- xen/arch/x86/x86_32/mm.c | 10 ++-- xen/arch/x86/x86_64/mm.c | 10 ++-- xen/common/memory.c | 79 ++++++++++++++++--------------- xen/common/multicall.c | 4 +- xen/drivers/char/console.c | 5 +- xen/include/asm-x86/mm.h | 4 +- xen/include/public/memory.h | 12 +++-- xen/include/public/xen.h | 16 +++++++ xen/include/xen/guest_access.h | 71 +++++++++++++++++++++++++++ xen/include/xen/sched.h | 37 +++++---------- 16 files changed, 243 insertions(+), 162 deletions(-) create mode 100644 xen/include/xen/guest_access.h diff --git a/xen/Rules.mk b/xen/Rules.mk index 25478ec434..8fbae5270f 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -45,7 +45,7 @@ ALL_OBJS += $(BASEDIR)/arch/$(TARGET_ARCH)/arch.o include $(BASEDIR)/arch/$(TARGET_ARCH)/Rules.mk -CFLAGS += -g +CFLAGS += -g -D__XEN__ ifneq ($(debug),y) CFLAGS += -DNDEBUG diff --git a/xen/arch/ia64/vmx/vmx_hypercall.c b/xen/arch/ia64/vmx/vmx_hypercall.c index 75c1cc9fb2..b7fde636e7 100644 --- a/xen/arch/ia64/vmx/vmx_hypercall.c +++ b/xen/arch/ia64/vmx/vmx_hypercall.c @@ -52,45 +52,7 @@ void hyper_mmu_update(void) vcpu_set_gr(vcpu, 8, ret, 0); vmx_vcpu_increment_iip(vcpu); } -/* turn off temporarily, we will merge hypercall parameter convention with xeno, when - VTI domain need to call hypercall */ -#if 0 -unsigned long __hypercall_create_continuation( - unsigned int op, unsigned int nr_args, ...) -{ - struct mc_state *mcs = &mc_state[smp_processor_id()]; - VCPU *vcpu = current; - struct cpu_user_regs *regs = vcpu_regs(vcpu); - unsigned int i; - va_list args; - - va_start(args, nr_args); - if ( test_bit(_MCSF_in_multicall, &mcs->flags) ) { - panic("PREEMPT happen in multicall\n"); // Not support yet - } else { - vcpu_set_gr(vcpu, 15, op, 0); - for ( i = 0; i < nr_args; i++) { - switch (i) { - case 0: vcpu_set_gr(vcpu, 16, va_arg(args, unsigned long), 0); - break; - case 1: vcpu_set_gr(vcpu, 17, va_arg(args, unsigned long), 0); - break; - case 2: vcpu_set_gr(vcpu, 18, va_arg(args, unsigned long), 0); - break; - case 3: vcpu_set_gr(vcpu, 19, va_arg(args, unsigned long), 0); - break; - case 4: vcpu_set_gr(vcpu, 20, va_arg(args, unsigned long), 0); - break; - default: panic("Too many args for hypercall continuation\n"); - break; - } - } - } - vcpu->arch.hypercall_continuation = 1; - va_end(args); - return op; -} -#endif + void hyper_dom_mem_op(void) { VCPU *vcpu=current; diff --git a/xen/arch/ia64/xen/process.c b/xen/arch/ia64/xen/process.c index 0823c9423f..7ecfabf01e 100644 --- a/xen/arch/ia64/xen/process.c +++ b/xen/arch/ia64/xen/process.c @@ -796,31 +796,49 @@ printf("*** Handled privop masquerading as NaT fault\n"); reflect_interruption(isr,regs,vector); } -unsigned long __hypercall_create_continuation( - unsigned int op, unsigned int nr_args, ...) +unsigned long hypercall_create_continuation( + unsigned int op, const char *format, ...) { struct mc_state *mcs = &mc_state[smp_processor_id()]; VCPU *vcpu = current; struct cpu_user_regs *regs = vcpu_regs(vcpu); + const char *p = format; + unsigned long arg; unsigned int i; va_list args; - va_start(args, nr_args); + va_start(args, format); if ( test_bit(_MCSF_in_multicall, &mcs->flags) ) { panic("PREEMPT happen in multicall\n"); // Not support yet } else { vcpu_set_gr(vcpu, 2, op, 0); - for ( i = 0; i < nr_args; i++) { + for ( i = 0; *p != '\0'; i++) { + switch ( *p++ ) + { + case 'i': + arg = (unsigned long)va_arg(args, unsigned int); + break; + case 'l': + arg = (unsigned long)va_arg(args, unsigned long); + break; + case 'p': + case 'h': + arg = (unsigned long)va_arg(args, void *); + break; + default: + arg = 0; + BUG(); + } switch (i) { - case 0: vcpu_set_gr(vcpu, 14, va_arg(args, unsigned long), 0); + case 0: vcpu_set_gr(vcpu, 14, arg, 0); break; - case 1: vcpu_set_gr(vcpu, 15, va_arg(args, unsigned long), 0); + case 1: vcpu_set_gr(vcpu, 15, arg, 0); break; - case 2: vcpu_set_gr(vcpu, 16, va_arg(args, unsigned long), 0); + case 2: vcpu_set_gr(vcpu, 16, arg, 0); break; - case 3: vcpu_set_gr(vcpu, 17, va_arg(args, unsigned long), 0); + case 3: vcpu_set_gr(vcpu, 17, arg, 0); break; - case 4: vcpu_set_gr(vcpu, 18, va_arg(args, unsigned long), 0); + case 4: vcpu_set_gr(vcpu, 18, arg, 0); break; default: panic("Too many args for hypercall continuation\n"); break; diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index df61b9b9aa..b383683e70 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -825,22 +825,37 @@ void sync_vcpu_execstate(struct vcpu *v) flush_tlb_mask(v->vcpu_dirty_cpumask); } -unsigned long __hypercall_create_continuation( - unsigned int op, unsigned int nr_args, ...) +#define next_arg(fmt, args) ({ \ + unsigned long __arg; \ + switch ( *(fmt)++ ) \ + { \ + case 'i': __arg = (unsigned long)va_arg(args, unsigned int); break; \ + case 'l': __arg = (unsigned long)va_arg(args, unsigned long); break; \ + case 'p': __arg = (unsigned long)va_arg(args, void *); break; \ + case 'h': __arg = (unsigned long)va_arg(args, void *); break; \ + default: __arg = 0; BUG(); \ + } \ + __arg; \ +}) + +unsigned long hypercall_create_continuation( + unsigned int op, const char *format, ...) { struct mc_state *mcs = &mc_state[smp_processor_id()]; struct cpu_user_regs *regs; + const char *p = format; + unsigned long arg; unsigned int i; va_list args; - va_start(args, nr_args); + va_start(args, format); if ( test_bit(_MCSF_in_multicall, &mcs->flags) ) { __set_bit(_MCSF_call_preempted, &mcs->flags); - for ( i = 0; i < nr_args; i++ ) - mcs->call.args[i] = va_arg(args, unsigned long); + for ( i = 0; *p != '\0'; i++ ) + mcs->call.args[i] = next_arg(p, args); } else { @@ -853,32 +868,34 @@ unsigned long __hypercall_create_continuation( else regs->eip -= 2; /* re-execute 'int 0x82' */ - for ( i = 0; i < nr_args; i++ ) + for ( i = 0; *p != '\0'; i++ ) { + arg = next_arg(p, args); switch ( i ) { - case 0: regs->ebx = va_arg(args, unsigned long); break; - case 1: regs->ecx = va_arg(args, unsigned long); break; - case 2: regs->edx = va_arg(args, unsigned long); break; - case 3: regs->esi = va_arg(args, unsigned long); break; - case 4: regs->edi = va_arg(args, unsigned long); break; - case 5: regs->ebp = va_arg(args, unsigned long); break; + case 0: regs->ebx = arg; break; + case 1: regs->ecx = arg; break; + case 2: regs->edx = arg; break; + case 3: regs->esi = arg; break; + case 4: regs->edi = arg; break; + case 5: regs->ebp = arg; break; } } #elif defined(__x86_64__) regs->rax = op; regs->rip -= 2; /* re-execute 'syscall' */ - for ( i = 0; i < nr_args; i++ ) + for ( i = 0; *p != '\0'; i++ ) { + arg = next_arg(p, args); switch ( i ) { - case 0: regs->rdi = va_arg(args, unsigned long); break; - case 1: regs->rsi = va_arg(args, unsigned long); break; - case 2: regs->rdx = va_arg(args, unsigned long); break; - case 3: regs->r10 = va_arg(args, unsigned long); break; - case 4: regs->r8 = va_arg(args, unsigned long); break; - case 5: regs->r9 = va_arg(args, unsigned long); break; + case 0: regs->rdi = arg; break; + case 1: regs->rsi = arg; break; + case 2: regs->rdx = arg; break; + case 3: regs->r10 = arg; break; + case 4: regs->r8 = arg; break; + case 5: regs->r9 = arg; break; } } #endif diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 371cc78279..321d2b9dee 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -97,11 +97,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -1778,9 +1778,9 @@ int do_mmuext_op( { if ( hypercall_preempt_check() ) { - rc = hypercall4_create_continuation( - __HYPERVISOR_mmuext_op, uops, - (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom); + rc = hypercall_create_continuation( + __HYPERVISOR_mmuext_op, "pipi", + uops, (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom); break; } @@ -2044,9 +2044,9 @@ int do_mmu_update( { if ( hypercall_preempt_check() ) { - rc = hypercall4_create_continuation( - __HYPERVISOR_mmu_update, ureqs, - (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom); + rc = hypercall_create_continuation( + __HYPERVISOR_mmu_update, "pipi", + ureqs, (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom); break; } @@ -2795,7 +2795,7 @@ long do_update_descriptor(u64 pa, u64 desc) } -long arch_memory_op(int op, void *arg) +long arch_memory_op(int op, GUEST_HANDLE(void) arg) { struct xen_reserved_phys_area xrpa; unsigned long pfn; @@ -2805,7 +2805,7 @@ long arch_memory_op(int op, void *arg) switch ( op ) { case XENMEM_reserved_phys_area: - if ( copy_from_user(&xrpa, arg, sizeof(xrpa)) ) + if ( copy_from_guest(&xrpa, arg, 1) ) return -EFAULT; /* No guest has more than one reserved area. */ @@ -2839,7 +2839,7 @@ long arch_memory_op(int op, void *arg) put_domain(d); - if ( copy_to_user(arg, &xrpa, sizeof(xrpa)) ) + if ( copy_to_guest(arg, &xrpa, 1) ) return -EFAULT; break; diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index bd590c70ce..2dabc44c31 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1415,8 +1415,8 @@ long do_set_trap_table(struct trap_info *traps) { if ( hypercall_preempt_check() ) { - rc = hypercall1_create_continuation( - __HYPERVISOR_set_trap_table, traps); + rc = hypercall_create_continuation( + __HYPERVISOR_set_trap_table, "p", traps); break; } diff --git a/xen/arch/x86/x86_32/mm.c b/xen/arch/x86/x86_32/mm.c index 70dfe77bab..19dfc0170e 100644 --- a/xen/arch/x86/x86_32/mm.c +++ b/xen/arch/x86/x86_32/mm.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -191,7 +192,7 @@ void subarch_init_memory(struct domain *dom_xen) } } -long subarch_memory_op(int op, void *arg) +long subarch_memory_op(int op, GUEST_HANDLE(void) arg) { struct xen_machphys_mfn_list xmml; unsigned long mfn; @@ -201,7 +202,7 @@ long subarch_memory_op(int op, void *arg) switch ( op ) { case XENMEM_machphys_mfn_list: - if ( copy_from_user(&xmml, arg, sizeof(xmml)) ) + if ( copy_from_guest(&xmml, arg, 1) ) return -EFAULT; max = min_t(unsigned int, xmml.max_extents, mpt_size >> 21); @@ -210,11 +211,12 @@ long subarch_memory_op(int op, void *arg) { mfn = l2e_get_pfn(idle_pg_table_l2[l2_linear_offset( RDWR_MPT_VIRT_START + (i << 21))]) + l1_table_offset(i << 21); - if ( put_user(mfn, &xmml.extent_start[i]) ) + if ( copy_to_guest_offset(xmml.extent_start, i, &mfn, 1) ) return -EFAULT; } - if ( put_user(i, &((struct xen_machphys_mfn_list *)arg)->nr_extents) ) + xmml.nr_extents = i; + if ( copy_to_guest(arg, &xmml, 1) ) return -EFAULT; break; diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c index 855a6510f2..7e826da8b0 100644 --- a/xen/arch/x86/x86_64/mm.c +++ b/xen/arch/x86/x86_64/mm.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -182,7 +183,7 @@ void subarch_init_memory(struct domain *dom_xen) } } -long subarch_memory_op(int op, void *arg) +long subarch_memory_op(int op, GUEST_HANDLE(void) arg) { struct xen_machphys_mfn_list xmml; l3_pgentry_t l3e; @@ -194,7 +195,7 @@ long subarch_memory_op(int op, void *arg) switch ( op ) { case XENMEM_machphys_mfn_list: - if ( copy_from_user(&xmml, arg, sizeof(xmml)) ) + if ( copy_from_guest(&xmml, arg, 1) ) return -EFAULT; for ( i = 0, v = RDWR_MPT_VIRT_START; @@ -209,11 +210,12 @@ long subarch_memory_op(int op, void *arg) if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) break; mfn = l2e_get_pfn(l2e) + l1_table_offset(v); - if ( put_user(mfn, &xmml.extent_start[i]) ) + if ( copy_to_guest_offset(xmml.extent_start, i, &mfn, 1) ) return -EFAULT; } - if ( put_user(i, &((struct xen_machphys_mfn_list *)arg)->nr_extents) ) + xmml.nr_extents = i; + if ( copy_to_guest(arg, &xmml, 1) ) return -EFAULT; break; diff --git a/xen/common/memory.c b/xen/common/memory.c index 40a2d9c14d..4d96f97465 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -30,7 +31,7 @@ static long increase_reservation( struct domain *d, - unsigned long *extent_list, + GUEST_HANDLE(xen_ulong) extent_list, unsigned int nr_extents, unsigned int extent_order, unsigned int flags, @@ -39,8 +40,8 @@ increase_reservation( struct page_info *page; unsigned long i, mfn; - if ( (extent_list != NULL) && - !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) ) + if ( !guest_handle_is_null(extent_list) && + !guest_handle_okay(extent_list, nr_extents) ) return 0; if ( (extent_order != 0) && @@ -65,10 +66,10 @@ increase_reservation( } /* Inform the domain of the new page's machine address. */ - if ( extent_list != NULL ) + if ( !guest_handle_is_null(extent_list) ) { mfn = page_to_mfn(page); - if ( unlikely(__copy_to_user(&extent_list[i], &mfn, sizeof(mfn))) ) + if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) ) return i; } } @@ -79,16 +80,16 @@ increase_reservation( static long populate_physmap( struct domain *d, - unsigned long *extent_list, - unsigned int nr_extents, - unsigned int extent_order, - unsigned int flags, - int *preempted) + GUEST_HANDLE(xen_ulong) extent_list, + unsigned int nr_extents, + unsigned int extent_order, + unsigned int flags, + int *preempted) { struct page_info *page; unsigned long i, j, gpfn, mfn; - if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) ) + if ( !guest_handle_okay(extent_list, nr_extents) ) return 0; if ( (extent_order != 0) && @@ -103,7 +104,7 @@ populate_physmap( goto out; } - if ( unlikely(__copy_from_user(&gpfn, &extent_list[i], sizeof(gpfn))) ) + if ( unlikely(__copy_from_guest_offset(&gpfn, extent_list, i, 1)) ) goto out; if ( unlikely((page = alloc_domheap_pages( @@ -128,7 +129,7 @@ populate_physmap( set_gpfn_from_mfn(mfn + j, gpfn + j); /* Inform the domain of the new page's machine address. */ - if ( unlikely(__copy_to_user(&extent_list[i], &mfn, sizeof(mfn))) ) + if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) ) goto out; } } @@ -139,8 +140,8 @@ populate_physmap( static long decrease_reservation( - struct domain *d, - unsigned long *extent_list, + struct domain *d, + GUEST_HANDLE(xen_ulong) extent_list, unsigned int nr_extents, unsigned int extent_order, unsigned int flags, @@ -149,7 +150,7 @@ decrease_reservation( struct page_info *page; unsigned long i, j, gmfn, mfn; - if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) ) + if ( !guest_handle_okay(extent_list, nr_extents) ) return 0; for ( i = 0; i < nr_extents; i++ ) @@ -160,7 +161,7 @@ decrease_reservation( return i; } - if ( unlikely(__copy_from_user(&gmfn, &extent_list[i], sizeof(gmfn))) ) + if ( unlikely(__copy_from_guest_offset(&gmfn, extent_list, i, 1)) ) return i; for ( j = 0; j < (1 << extent_order); j++ ) @@ -197,21 +198,21 @@ decrease_reservation( static long translate_gpfn_list( - struct xen_translate_gpfn_list *uop, unsigned long *progress) + GUEST_HANDLE(xen_translate_gpfn_list_t) uop, unsigned long *progress) { struct xen_translate_gpfn_list op; unsigned long i, gpfn, mfn; struct domain *d; - if ( copy_from_user(&op, uop, sizeof(op)) ) + if ( copy_from_guest(&op, uop, 1) ) return -EFAULT; /* Is size too large for us to encode a continuation? */ if ( op.nr_gpfns > (ULONG_MAX >> START_EXTENT_SHIFT) ) return -EINVAL; - if ( !array_access_ok(op.gpfn_list, op.nr_gpfns, sizeof(*op.gpfn_list)) || - !array_access_ok(op.mfn_list, op.nr_gpfns, sizeof(*op.mfn_list)) ) + if ( !guest_handle_okay(op.gpfn_list, op.nr_gpfns) || + !guest_handle_okay(op.mfn_list, op.nr_gpfns) ) return -EFAULT; if ( op.domid == DOMID_SELF ) @@ -237,8 +238,7 @@ translate_gpfn_list( return -EAGAIN; } - if ( unlikely(__copy_from_user(&gpfn, &op.gpfn_list[i], - sizeof(gpfn))) ) + if ( unlikely(__copy_from_guest_offset(&gpfn, op.gpfn_list, i, 1)) ) { put_domain(d); return -EFAULT; @@ -246,8 +246,7 @@ translate_gpfn_list( mfn = gmfn_to_mfn(d, gpfn); - if ( unlikely(__copy_to_user(&op.mfn_list[i], &mfn, - sizeof(mfn))) ) + if ( unlikely(__copy_to_guest_offset(op.mfn_list, i, &mfn, 1)) ) { put_domain(d); return -EFAULT; @@ -258,7 +257,7 @@ translate_gpfn_list( return 0; } -long do_memory_op(unsigned long cmd, void *arg) +long do_memory_op(unsigned long cmd, GUEST_HANDLE(void) arg) { struct domain *d; int rc, op, flags = 0, preempted = 0; @@ -273,7 +272,7 @@ long do_memory_op(unsigned long cmd, void *arg) case XENMEM_increase_reservation: case XENMEM_decrease_reservation: case XENMEM_populate_physmap: - if ( copy_from_user(&reservation, arg, sizeof(reservation)) ) + if ( copy_from_guest(&reservation, arg, 1) ) return -EFAULT; /* Is size too large for us to encode a continuation? */ @@ -283,9 +282,9 @@ long do_memory_op(unsigned long cmd, void *arg) start_extent = cmd >> START_EXTENT_SHIFT; if ( unlikely(start_extent > reservation.nr_extents) ) return -EINVAL; - - if ( reservation.extent_start != NULL ) - reservation.extent_start += start_extent; + + if ( !guest_handle_is_null(reservation.extent_start) ) + guest_handle_add_offset(reservation.extent_start, start_extent); reservation.nr_extents -= start_extent; if ( (reservation.address_bits != 0) && @@ -342,8 +341,9 @@ long do_memory_op(unsigned long cmd, void *arg) rc += start_extent; if ( preempted ) - return hypercall2_create_continuation( - __HYPERVISOR_memory_op, op | (rc << START_EXTENT_SHIFT), arg); + return hypercall_create_continuation( + __HYPERVISOR_memory_op, "lh", + op | (rc << START_EXTENT_SHIFT), arg); break; @@ -353,10 +353,10 @@ long do_memory_op(unsigned long cmd, void *arg) case XENMEM_current_reservation: case XENMEM_maximum_reservation: - if ( copy_from_user(&domid, (domid_t *)arg, sizeof(domid)) ) + if ( copy_from_guest(&domid, arg, 1) ) return -EFAULT; - if ( likely((domid = (unsigned long)arg) == DOMID_SELF) ) + if ( likely(domid == DOMID_SELF) ) d = current->domain; else if ( !IS_PRIV(current->domain) ) return -EPERM; @@ -372,12 +372,13 @@ long do_memory_op(unsigned long cmd, void *arg) case XENMEM_translate_gpfn_list: progress = cmd >> START_EXTENT_SHIFT; - rc = translate_gpfn_list(arg, &progress); + rc = translate_gpfn_list( + guest_handle_cast(arg, xen_translate_gpfn_list_t), + &progress); if ( rc == -EAGAIN ) - return hypercall2_create_continuation( - __HYPERVISOR_memory_op, - op | (progress << START_EXTENT_SHIFT), - arg); + return hypercall_create_continuation( + __HYPERVISOR_memory_op, "lh", + op | (progress << START_EXTENT_SHIFT), arg); break; default: diff --git a/xen/common/multicall.c b/xen/common/multicall.c index d6473a8b4b..823625aad1 100644 --- a/xen/common/multicall.c +++ b/xen/common/multicall.c @@ -81,8 +81,8 @@ long do_multicall(struct multicall_entry *call_list, unsigned int nr_calls) if ( i < nr_calls ) { mcs->flags = 0; - return hypercall2_create_continuation( - __HYPERVISOR_multicall, &call_list[i], nr_calls-i); + return hypercall_create_continuation( + __HYPERVISOR_multicall, "pi", &call_list[i], nr_calls-i); } } } diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index c11fbf4cf4..7c8b0d6baa 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -335,8 +335,9 @@ long guest_console_write(char *buffer, int count) } if ( hypercall_preempt_check() ) - return hypercall3_create_continuation( - __HYPERVISOR_console_io, CONSOLEIO_write, count, buffer); + return hypercall_create_continuation( + __HYPERVISOR_console_io, "iip", + CONSOLEIO_write, count, buffer); kcount = min_t(int, count, sizeof(kbuf)-1); if ( copy_from_user(kbuf, buffer, kcount) ) diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index 468427b099..4d7870fb03 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -376,7 +376,7 @@ void propagate_page_fault(unsigned long addr, u16 error_code); int __sync_lazy_execstate(void); /* Arch-specific portion of memory_op hypercall. */ -long arch_memory_op(int op, void *arg); -long subarch_memory_op(int op, void *arg); +long arch_memory_op(int op, GUEST_HANDLE(void) arg); +long subarch_memory_op(int op, GUEST_HANDLE(void) arg); #endif /* __ASM_X86_MM_H__ */ diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h index eb99be99ef..639c293b27 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -29,7 +29,7 @@ typedef struct xen_memory_reservation { * OUT: GMFN bases of extents that were allocated * (NB. This command also updates the mach_to_phys translation table) */ - unsigned long *extent_start; + GUEST_HANDLE(xen_ulong) extent_start; /* Number of extents, and size/alignment of each (2^extent_order pages). */ unsigned long nr_extents; @@ -50,6 +50,7 @@ typedef struct xen_memory_reservation { domid_t domid; } xen_memory_reservation_t; +DEFINE_GUEST_HANDLE(xen_memory_reservation_t); /* * Returns the maximum machine frame number of mapped RAM in this system. @@ -85,7 +86,7 @@ typedef struct xen_machphys_mfn_list { * any large discontiguities in the machine address space, 2MB gaps in * the machphys table will be represented by an MFN base of zero. */ - unsigned long *extent_start; + GUEST_HANDLE(xen_ulong) extent_start; /* * Number of extents written to the above array. This will be smaller @@ -93,6 +94,7 @@ typedef struct xen_machphys_mfn_list { */ unsigned int nr_extents; } xen_machphys_mfn_list_t; +DEFINE_GUEST_HANDLE(xen_machphys_mfn_list_t); /* * Returns the base and size of the specified reserved 'RAM hole' in the @@ -113,6 +115,7 @@ typedef struct xen_reserved_phys_area { /* Base and size of the specified reserved area. */ unsigned long first_gpfn, nr_gpfns; } xen_reserved_phys_area_t; +DEFINE_GUEST_HANDLE(xen_reserved_phys_area_t); /* * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error @@ -127,14 +130,15 @@ typedef struct xen_translate_gpfn_list { unsigned long nr_gpfns; /* List of GPFNs to translate. */ - unsigned long *gpfn_list; + GUEST_HANDLE(xen_ulong) gpfn_list; /* * Output list to contain MFN translations. May be the same as the input * list (in which case each input GPFN is overwritten with the output MFN). */ - unsigned long *mfn_list; + GUEST_HANDLE(xen_ulong) mfn_list; } xen_translate_gpfn_list_t; +DEFINE_GUEST_HANDLE(xen_translate_gpfn_list_t); #endif /* __XEN_PUBLIC_MEMORY_H__ */ diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index 9baf7f0bbe..a629a1e26a 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -9,6 +9,22 @@ #ifndef __XEN_PUBLIC_XEN_H__ #define __XEN_PUBLIC_XEN_H__ +#ifdef __XEN__ +#define DEFINE_GUEST_HANDLE(type) struct __guest_handle_ ## type { type *p; } +#define GUEST_HANDLE(type) struct __guest_handle_ ## type +#else +#define DEFINE_GUEST_HANDLE(type) +#define GUEST_HANDLE(type) type * +#endif + +#ifndef __ASSEMBLY__ +/* Guest handle for unsigned long pointer. Define a name with no whitespace. */ +typedef unsigned long xen_ulong; +DEFINE_GUEST_HANDLE(xen_ulong); +/* Guest handle for arbitrary-type pointer (void *). */ +DEFINE_GUEST_HANDLE(void); +#endif + #if defined(__i386__) #include "arch-x86_32.h" #elif defined(__x86_64__) diff --git a/xen/include/xen/guest_access.h b/xen/include/xen/guest_access.h new file mode 100644 index 0000000000..3a5bba9f0b --- /dev/null +++ b/xen/include/xen/guest_access.h @@ -0,0 +1,71 @@ +/****************************************************************************** + * guest_access.h + * + * Copyright (x) 2006, K A Fraser + */ + +#ifndef __XEN_GUEST_ACCESS_H__ +#define __XEN_GUEST_ACCESS_H__ + +#include + +/* Is the guest handle a NULL reference? */ +#define guest_handle_is_null(hnd) ((hnd).p == NULL) + +/* Offset the given guest handle into the array it refers to. */ +#define guest_handle_add_offset(hnd, nr) ((hnd).p += (nr)) + +/* Cast a guest handle to the specified type of handle. */ +#define guest_handle_cast(hnd, type) ({ \ + type *_x = (hnd).p; \ + (GUEST_HANDLE(type)) { _x }; \ +}) + +/* + * Copy an array of objects to guest context via a guest handle. + * Optionally specify an offset into the guest array. + */ +#define copy_to_guest_offset(hnd, off, ptr, nr) ({ \ + const typeof(ptr) _x = (hnd).p; \ + const typeof(ptr) _y = (ptr); \ + copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ +}) +#define copy_to_guest(hnd, ptr, nr) \ + copy_to_guest_offset(hnd, 0, ptr, nr) + +/* + * Copy an array of objects from guest context via a guest handle. + * Optionally specify an offset into the guest array. + */ +#define copy_from_guest_offset(ptr, hnd, off, nr) ({ \ + const typeof(ptr) _x = (hnd).p; \ + const typeof(ptr) _y = (ptr); \ + copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ +}) +#define copy_from_guest(ptr, hnd, nr) \ + copy_from_guest_offset(ptr, hnd, 0, nr) + +/* + * Pre-validate a guest handle. + * Allows use of faster __copy_* functions. + */ +#define guest_handle_okay(hnd, nr) \ + array_access_ok((hnd).p, (nr), sizeof(*(hnd).p)) + +#define __copy_to_guest_offset(hnd, off, ptr, nr) ({ \ + const typeof(ptr) _x = (hnd).p; \ + const typeof(ptr) _y = (ptr); \ + __copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ +}) +#define __copy_to_guest(hnd, ptr, nr) \ + __copy_to_guest_offset(hnd, 0, ptr, nr) + +#define __copy_from_guest_offset(ptr, hnd, off, nr) ({ \ + const typeof(ptr) _x = (hnd).p; \ + const typeof(ptr) _y = (ptr); \ + __copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ +}) +#define __copy_from_guest(ptr, hnd, nr) \ + __copy_from_guest_offset(ptr, hnd, 0, nr) + +#endif /* __XEN_GUEST_ACCESS_H__ */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 91f457702a..2d9c5564d1 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -303,31 +303,18 @@ extern void continue_running( void startup_cpu_idle_loop(void); -unsigned long __hypercall_create_continuation( - unsigned int op, unsigned int nr_args, ...); -#define hypercall0_create_continuation(_op) \ - __hypercall_create_continuation((_op), 0) -#define hypercall1_create_continuation(_op, _a1) \ - __hypercall_create_continuation((_op), 1, \ - (unsigned long)(_a1)) -#define hypercall2_create_continuation(_op, _a1, _a2) \ - __hypercall_create_continuation((_op), 2, \ - (unsigned long)(_a1), (unsigned long)(_a2)) -#define hypercall3_create_continuation(_op, _a1, _a2, _a3) \ - __hypercall_create_continuation((_op), 3, \ - (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3)) -#define hypercall4_create_continuation(_op, _a1, _a2, _a3, _a4) \ - __hypercall_create_continuation((_op), 4, \ - (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \ - (unsigned long)(_a4)) -#define hypercall5_create_continuation(_op, _a1, _a2, _a3, _a4, _a5) \ - __hypercall_create_continuation((_op), 5, \ - (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \ - (unsigned long)(_a4), (unsigned long)(_a5)) -#define hypercall6_create_continuation(_op, _a1, _a2, _a3, _a4, _a5, _a6) \ - __hypercall_create_continuation((_op), 6, \ - (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \ - (unsigned long)(_a4), (unsigned long)(_a5), (unsigned long)(_a6)) +/* + * Creates a continuation to resume the current hypercall. The caller should + * return immediately, propagating the value returned from this invocation. + * The format string specifies the types and number of hypercall arguments. + * It contains one character per argument as follows: + * 'i' [unsigned] {char, int} + * 'l' [unsigned] long + * 'p' pointer (foo *) + * 'h' guest handle (GUEST_HANDLE(foo)) + */ +unsigned long hypercall_create_continuation( + unsigned int op, const char *format, ...); #define hypercall_preempt_check() (unlikely( \ softirq_pending(smp_processor_id()) | \ -- 2.30.2